package org.kca.yarmour.view;

import java.awt.Color;
import java.util.List;
import static org.lwjgl.opengl.GL11.*;
import org.kca.yarmour.data.Player;
import org.kca.yarmour.data.Quest;
import org.kca.yarmour.utils.KcaGLUtils;

public class QuestListDialog extends PopupDialog
{
    private static final int DIALOG_WIDTH = 600;
    private static final int DIALOG_HEIGHT = 400;
    private static final int RIGHT_PANEL_X = 300;
    private static final int SCBAR_W = 16;
    private static final int SCBAR_DRAG_THRESHOLD = 50;
    private static final int BUTTON_PANEL_Y = DIALOG_HEIGHT - 40;
    private static final int TAB_HEIGHT = 25;
    private static final int TAB_MID_WIDTH = 70;
    private static final int TAB_GRAD_WIDTH = 6;
    private static final int QUEST_NAME_X = 10;
    private static final int QUEST_NAME_Y_OFFSET = 4;
    private static final int ENTRY_HEIGHT = 40;
    
    private static final Color AVAILABLE_COLOR = new Color(160, 255, 255);
    private static final Color READY_TO_CP_COLOR = new Color(127, 255, 127);
    private static final Color ACTIVE_COLOR = new Color(255, 255, 160);
    private static final Color COMPLETED_COLOR = new Color(192, 192, 192);
    private final static Color SCBAR_COLOR = new Color(128, 128, 128);
    
    private int activeTab;
    private Player player;
    private List<Quest> availableQuests;
    private int totalQuests1, scrPos1, scrPos2;
    private boolean scrollDragged1;
    private int scDragY1, scTopY1;
    
    public QuestListDialog()
    {
        super(DIALOG_WIDTH, DIALOG_HEIGHT, "Quests");
        activeTab = 0;
        scrPos1 = 0;
        scrPos2 = 0;
        scrollDragged1 = false;
    }
    
    /**
     * Initializes the quest dialog by providing with handles to objects containing quest lists
     * @param p the player object
     */
    public void initQuestDialog(Player p)
    {
        this.player = p;
    }
    
    /**
     * Sets the list of available quests to display
     * @param availableQuests the list of available quests
     */
    public void initAvailableQuests(List<Quest> availableQuests)
    {
        this.availableQuests = availableQuests;
    }
    
    /**
     * This method must be called to refresh the UI when the quest list is updated, such as 
     * when quests are completed, accepted, or when opening the quest list in a new location
     */
    public void questsUpdated()
    {
        if (activeTab == 0)
        {
            totalQuests1 = availableQuests.size() + player.getActiveQuests().size();
        }
    }
    
    @Override
    protected void drawContent()
    {
        // draw tab row
        KcaGLUtils.drawTabs(BORDER_WIDTH, TITLEBAR_HEIGHT, RIGHT_PANEL_X - BORDER_WIDTH, 
                TAB_HEIGHT, TAB_MID_WIDTH, TAB_GRAD_WIDTH, 
                new String[] {"Current", "Completed"}, DIALOG_FONT, activeTab);
        
        int basey = TITLEBAR_HEIGHT + TAB_HEIGHT;
        if (activeTab == 0)
        {
            int tempPos1 = scrPos1;
            int visHeight = BUTTON_PANEL_Y - basey;
            int sbTotalHeight = visHeight - 2 * SCBAR_W;
            int totalHeight = totalQuests1 * ENTRY_HEIGHT;
            
            if (scrollDragged1)
            {
                int newtopy = scTopY1 + getMouseY() - scDragY1;
                int scbarh = Math.round(sbTotalHeight * visHeight / (float) totalHeight);
                newtopy = Math.max(0, newtopy);
                newtopy = Math.min(sbTotalHeight - scbarh, newtopy);
                tempPos1 = Math.round(newtopy * totalHeight / (float)sbTotalHeight);
            }
            if (totalQuests1 > 0)
            {
                // draw active quest list
                int topidx = tempPos1 / ENTRY_HEIGHT;
                int starth = ENTRY_HEIGHT - tempPos1 % ENTRY_HEIGHT;
             
                int ty = basey + ENTRY_HEIGHT - tempPos1 % ENTRY_HEIGHT;
                {
                    // draw topmost entry partially
                    Quest q = getCurrentQuest(topidx);
                    Color ec = getQuestColor(q);
                    KcaGLUtils.setColor(ec);
                    KcaGLUtils.fillRect(BORDER_WIDTH, basey, RIGHT_PANEL_X - SCBAR_W - BORDER_WIDTH, 
                            starth);
                    glColor4f(0, 0, 0, 1);
                    KcaGLUtils.drawLine(BORDER_WIDTH + 1, basey, BORDER_WIDTH + 1, basey + starth);
                    KcaGLUtils.drawLine(BORDER_WIDTH, ty, RIGHT_PANEL_X - SCBAR_W - BORDER_WIDTH + 1, ty);
                    DIALOG_FONT.drawPartialString(q.getDetails().getName(), 
                            QUEST_NAME_X, basey - tempPos1 % ENTRY_HEIGHT + QUEST_NAME_Y_OFFSET,
                            QUEST_NAME_X, basey, RIGHT_PANEL_X - SCBAR_W - BORDER_WIDTH, starth);
                }
                // draw 2nd and subsequent entries
                for (topidx++; ty + ENTRY_HEIGHT < BUTTON_PANEL_Y && topidx < totalQuests1; 
                        ty += ENTRY_HEIGHT, topidx++)
                {
                    Quest q = getCurrentQuest(topidx);
                    Color ec = getQuestColor(q);
                    KcaGLUtils.setColor(ec);
                    KcaGLUtils.fillRect(BORDER_WIDTH, ty, RIGHT_PANEL_X - SCBAR_W - BORDER_WIDTH, 
                            ENTRY_HEIGHT);
                    glColor4f(0, 0, 0, 1);
                    KcaGLUtils.drawRect(BORDER_WIDTH, ty, RIGHT_PANEL_X - SCBAR_W - BORDER_WIDTH, 
                            ENTRY_HEIGHT);
                    DIALOG_FONT.drawString(q.getDetails().getName(), QUEST_NAME_X, 
                            ty + QUEST_NAME_Y_OFFSET);
                }
                // draw last entry
                if (topidx < totalQuests1)
                {
                    Quest q = getCurrentQuest(topidx);
                    Color ec = getQuestColor(q);
                    KcaGLUtils.setColor(ec);
                    KcaGLUtils.fillRect(BORDER_WIDTH, ty, RIGHT_PANEL_X - SCBAR_W - BORDER_WIDTH, 
                            BUTTON_PANEL_Y - ty);
                    glColor4f(0, 0, 0, 1);
                    KcaGLUtils.drawLine(BORDER_WIDTH, ty + 1, RIGHT_PANEL_X - SCBAR_W - BORDER_WIDTH + 1, 
                            ty + 1);
                    KcaGLUtils.drawLine(BORDER_WIDTH + 1, ty, BORDER_WIDTH + 1, BUTTON_PANEL_Y);
                    DIALOG_FONT.drawPartialString(q.getDetails().getName(), QUEST_NAME_X, 
                            ty + QUEST_NAME_Y_OFFSET, BORDER_WIDTH, ty, 
                            RIGHT_PANEL_X - SCBAR_W - BORDER_WIDTH, BUTTON_PANEL_Y - ty);
                    
                }
            }
        
            // draw left scrollbar
            KcaGLUtils.setColor(SCBAR_COLOR);
            int scbarx = RIGHT_PANEL_X - SCBAR_W;
            if (totalHeight > visHeight)
            {
                int sbtopy = Math.round(tempPos1 * sbTotalHeight / (float)totalHeight);
                int sbboty = Math.round((tempPos1 + visHeight) * sbTotalHeight / (float)totalHeight);
                KcaGLUtils.fillRect(scbarx, basey + SCBAR_W + sbtopy, SCBAR_W - 1, 
                        sbboty - sbtopy);
            }
            else
            {
                // scrollbar occupies the entire height of box
                KcaGLUtils.fillRect(scbarx, basey + SCBAR_W, SCBAR_W - 1, 
                        sbTotalHeight - 1);
            }
            // draw left scrollbar lines and arrows
            glColor4f(0, 0, 0, 1);
            KcaGLUtils.drawLine(scbarx, basey + SCBAR_W, RIGHT_PANEL_X, basey + SCBAR_W);
            KcaGLUtils.drawLine(scbarx, BUTTON_PANEL_Y - SCBAR_W, 
                    RIGHT_PANEL_X, BUTTON_PANEL_Y - SCBAR_W);
            KcaGLUtils.drawLine(scbarx, basey + SCBAR_W - 4, scbarx + SCBAR_W / 2, 
                    basey + SCBAR_W / 2 - 4);
            KcaGLUtils.drawLine(scbarx + SCBAR_W / 2 - 1, basey + SCBAR_W / 2 - 4, 
                    scbarx + SCBAR_W - 1, basey + SCBAR_W - 4);
            KcaGLUtils.drawLine(scbarx, BUTTON_PANEL_Y - SCBAR_W + 4,
                    scbarx + SCBAR_W / 2, BUTTON_PANEL_Y - SCBAR_W / 2 + 4);
            KcaGLUtils.drawLine(scbarx + SCBAR_W / 2 - 1, BUTTON_PANEL_Y - SCBAR_W / 2 + 4, 
                    scbarx + SCBAR_W - 1, BUTTON_PANEL_Y - SCBAR_W + 4);
        }
        
        // draw dividers
        KcaGLUtils.drawLine(RIGHT_PANEL_X, TITLEBAR_HEIGHT, RIGHT_PANEL_X, DIALOG_HEIGHT);
        KcaGLUtils.drawLine(BORDER_WIDTH, BUTTON_PANEL_Y, DIALOG_WIDTH - BORDER_WIDTH, BUTTON_PANEL_Y);
        KcaGLUtils.drawLine(RIGHT_PANEL_X - SCBAR_W, basey, RIGHT_PANEL_X - SCBAR_W, BUTTON_PANEL_Y);
        KcaGLUtils.drawLine(DIALOG_WIDTH - BORDER_WIDTH - SCBAR_W, TITLEBAR_HEIGHT, 
                DIALOG_WIDTH - BORDER_WIDTH - SCBAR_W, BUTTON_PANEL_Y);
    }
    
    private void tabPressed(int tab)
    {
        if (activeTab == tab || tab < 0 || tab > 2)
        {
            return;
        }
        activeTab = tab;
        questsUpdated();
    }
    
    private void scrollLeftList(int amount)
    {
        int visHeight = BUTTON_PANEL_Y - TITLEBAR_HEIGHT - TAB_HEIGHT;
        int totalHeight = totalQuests1 * ENTRY_HEIGHT;
        switch (amount)
        {
        
        case -2:
            scrPos1 = Math.max(0, scrPos1 - visHeight);
            break;
        case -1:
            scrPos1 = Math.max(0, scrPos1 - 5);
            break;
        case 1:
            scrPos1 = Math.min(totalHeight - visHeight, scrPos1 + 5);
            break;
        case 2:
            scrPos1 = Math.min(totalHeight - visHeight, scrPos1 + visHeight);
            break;
        }
    }
    
    /**
     * Helper method to get active/available quest by index. All quests are arranged such
     * that available quests are first, followed by ready to complete quests, then active quests
     * @param index the quest index
     */
    private Quest getCurrentQuest(int index)
    {
        if (index < availableQuests.size()) 
        {
            return availableQuests.get(index);
        }
        else 
        {
            return player.getActiveQuests().get(index - availableQuests.size());
        }
    }
    
    /**
     * Helper method to get display color for different quest status
     * @param q the quest to get the color for
     * @return the display color, based on the quest status
     */
    private Color getQuestColor(Quest q)
    {
        switch (q.getStatus())
        {
        case AVAILABLE:
            return AVAILABLE_COLOR;
        case ACTIVE:
            return ACTIVE_COLOR;
        case READY_TO_COMPLETE:
            return READY_TO_CP_COLOR;
        case COMPLETED:
            return COMPLETED_COLOR;
        }
        return null;
    }
    
    @Override
    public void mousePressed(int button, int mx, int my)
    {
        boolean consumed = false;
        // Check for change of tab
        if (my >= TITLEBAR_HEIGHT && my < TITLEBAR_HEIGHT + TAB_HEIGHT)
        {
            for (int i = 0; i < 2; i++)
            {
                int xl = BORDER_WIDTH + (TAB_GRAD_WIDTH + TAB_MID_WIDTH) * i + TAB_GRAD_WIDTH;
                if (mx >= xl && mx < xl + TAB_MID_WIDTH)
                {
                    tabPressed(i);
                    return;
                }
            }
        }
        int basey = TITLEBAR_HEIGHT + TAB_HEIGHT;
        // check for clicks on scrollbar
        if (mx > RIGHT_PANEL_X - SCBAR_W && mx < RIGHT_PANEL_X && my > basey && my < BUTTON_PANEL_Y)
        {
            int visHeight = BUTTON_PANEL_Y - basey;
            int sbTotalHeight = visHeight - 2 * SCBAR_W;
            int totalHeight = totalQuests1 * ENTRY_HEIGHT;
            if (totalHeight <= visHeight)
            {
                return;
            }
            int sbtopy = Math.round(scrPos1 * sbTotalHeight / (float)totalHeight);
            int sbboty = Math.round((scrPos1 + visHeight) * sbTotalHeight / (float)totalHeight);
            if (my < basey + SCBAR_W)
            {
                scrollLeftList(-1);
            }
            else if (my < basey + SCBAR_W + sbtopy)
            {
                scrollLeftList(-2);
            }
            else if (my < basey + SCBAR_W + sbboty)
            {
                scrollDragged1 = true;
                scDragY1 = my;
                scTopY1 = sbtopy;
            }
            else if (my < BUTTON_PANEL_Y - SCBAR_W)
            {
                scrollLeftList(2);
            }
            else
            {
                scrollLeftList(1);
            }
        }
        
        if (!consumed)
        {
            super.mousePressed(button, mx, my);
        }
    }
    
    @Override
    public void mouseReleased(int button, int mx, int my)
    {
        if (button == 0)
        {
            if (scrollDragged1)
            {
                if (mx < RIGHT_PANEL_X - SCBAR_W - SCBAR_DRAG_THRESHOLD ||
                        mx > RIGHT_PANEL_X + SCBAR_DRAG_THRESHOLD)
                {
                    return;
                }
                int visHeight = BUTTON_PANEL_Y - TITLEBAR_HEIGHT - TAB_HEIGHT;
                int sbTotalHeight = visHeight - 2 * SCBAR_W;
                int totalHeight = totalQuests1 * ENTRY_HEIGHT;
                int newtopy = scTopY1 + my - scDragY1;
                int scbarh = Math.round(sbTotalHeight * visHeight / (float) totalHeight);
                newtopy = Math.max(0, newtopy);
                newtopy = Math.min(sbTotalHeight - scbarh, newtopy);
                scrPos1 = Math.round(newtopy * totalHeight / (float)sbTotalHeight);
                System.out.println("Released at " + newtopy + ", height=" + scbarh + ", scrPos1=" + scrPos1);
                scrollDragged1 = false;
            }
        }
    }
}
